package Wormish.agiletre.se.Math;

import java.io.Serializable;

public class Vec2f implements Serializable{

	public static final Vec2f UnitX = new Vec2f(1, 0);
	public static final Vec2f UnitY = new Vec2f(0, 1);
	public static final Vec2f Zero = new Vec2f(0, 0);
	
	//Variables
	private float x, y;
	
	// --- Constructors
	public Vec2f(){
		x = 0.0f;
		y = 0.0f;
	}
	
	public Vec2f(float xNew, float yNew){
		this.setValues(xNew,yNew);
	}
	
	public Vec2f(Vec2f vec){
		x = vec.getX();
		y = vec.getY();
	}
	// --- End of constructors
	
	// --- Get methods
	public float getX(){
		return x;
	}
	
	public float getY(){
		return y;
	}
	
	public float getLength(){
		return (float)Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
	}
	// --- End of Get methods
	
	// --- Set methods
	public void setX(float xNew){
		x = xNew;
	}

	public void setY(float yNew){
		y = yNew;
	}
	
	public void setValues(float xNew, float yNew){
		x = xNew;
		y = yNew;
	}
	
	public void setValues(Vec2f vec){
		x = vec.getX();
		y = vec.getY();
	}
	// --- End of Set methods
	
	// --- Linear algebra: Add
	public void add(Vec2f vec){
		x += vec.getX();
		y += vec.getY();
	}
	
	public void add(float xAdd, float yAdd){
		x += xAdd;
		y += yAdd;
	}
	
	public Vec2f add(Vec2f vec, boolean createNewVector){
		if (createNewVector){
			return new Vec2f(x+vec.getX(),y+vec.getY());
		}
		else{
			this.add(vec);
			return null;
		}
	}
	
	public Vec2f add(float xAdd, float yAdd, boolean createNewVector){
		if (createNewVector){		
			return new Vec2f(x+xAdd,y+yAdd);
		}
		else{
			this.add(xAdd, yAdd);
			return null;
		}
	}
	// --- End of Linear algebra: Add
	
	// --- Linear algebra: Subtract
	public void subtract(Vec2f vec){
		x -= vec.getX();
		y -= vec.getY();
	}
	
	public void subtract(float xSub, float ySub){
		x -= xSub;
		y -= ySub;
	}
	
	public Vec2f subtract(Vec2f vec, boolean createNewVector){
		if (createNewVector){
			return new Vec2f(x-vec.getX(),y-vec.getY());
		}
		else{
			this.subtract(vec);
			return null;
		}
	}
	
	public Vec2f subtract(float xSub, float ySub, boolean createNewVector){
		if (createNewVector){		
			return new Vec2f(x-xSub,y-ySub);
		}
		else{
			this.subtract(xSub, ySub);
			return null;
		}
	}
	// --- End of Linear algebra: Subtract
	
	// Linear algebra: Misc.
	public float angle(Vec2f vec){
		return (float)Math.acos(this.dot(vec)/(this.getLength()*vec.getLength()));
	}
	
	public float dot(Vec2f vec){
		return x*vec.getX()+y*vec.getY();
	}
	
	public void invert(){
		x = -x;
		y = -y;
	}
	
	public void mirror(Vec2f vec){
		Vec2f vecProj = this.project(vec,true);
		vecProj.scale(2);
		this.subtract(vecProj);
		this.invert();
	}
	
	public void project(Vec2f vec){
		Vec2f vecProj = this.project(vec,true);
		this.setValues(vecProj);
	}
	
	public Vec2f project(Vec2f vec, boolean createNewVector){
		if (createNewVector){		
			return vec.scale(this.dot(vec)/(float)Math.pow(vec.getLength(),2),true);
		}
		else{
			this.project(vec);
			return null;	
		}
	}
	
	public void scale(float scaleFactor){
		x *= scaleFactor;
		y *= scaleFactor;
	}
	
	public void scale(int scaleFactor){
		x *= scaleFactor;
		y *= scaleFactor;
	}
	
	public Vec2f scale(float scaleFactor, boolean createNewVector){
		if (createNewVector){		
			return new Vec2f(x*scaleFactor,y*scaleFactor);
		}
		else{
			this.scale(scaleFactor);
			return null;
		}
	}
	
	public Vec2f scale(int scaleFactor, boolean createNewVector){
		if (createNewVector){		
			return new Vec2f(x*scaleFactor,y*scaleFactor);
		}
		else{
			this.scale(scaleFactor);
			return null;
		}
	}
	
	// End of Linear algebra: Misc.
	
	// Random good game play stuff
	
	public void trimMax(float maxVal){
		float length = getLength();
		if (length>maxVal){
			if (maxVal == 0.0){
				setValues(0f,0f);
			}
			else{
				scale(maxVal/length);
			}
		}
	}
	
	public void trimMin(float minVal){
		float length = getLength();
		if (length<minVal){
			if (minVal == 0.0){
				setValues(0f,0f);
			}
			else{
				scale(minVal/length);
			}

		}
	}
	
	public void normalize()
	{
		float length = this.getLength();
		
		x /= length;
		y /= length;
	}
	
	// End of Random good game play stuff
	
	public String toString(){
		return "x: "+x+"; y: "+y;
	}
	
	//Euclidian distance
	public float euclidianDistance(Vec2f v2){
		float distance = (float) Math.sqrt(Math.pow(this.x - v2.x, 2)+Math.pow(this.y - v2.y, 2));
		return distance;
	}
	//equals operator
	public boolean equals(Vec2f v){
		return (this.getX() == v.getX() && this.getY() == v.getY());
	}
}